﻿<cfsilent>
	<cfscript>
	
		jsonAdvice = getProperty("serviceFactory").getBean("jsonAdvice");
		mathAdvice = getProperty("serviceFactory").getBean("senateMathAdvice");	
		sequenceClassroomTimeTable = getProperty("serviceFactory").getBean("sequenceClassroomTimeTable");
		sequenceStudentExam = getProperty("serviceFactory").getBean("sequenceStudentExam");
		
		response = structNew();
		structInsert(response, "success", false, true);
		structInsert(response, "reason", "没有适合的考试时间", true);
		
		progress = [];
		rooms = [];

		examId = event.getArg("EXID");

		/* 加载考试任务 */
		sql = "SELECT exam_type, term_id, wid, cid, exidx, examer_sum,campus_id  
				FROM t_examtask 
				WHERE t_examtask.task_exid = :taskExid ";
					
		queryObj = new query( datasource=application.dnsSlave );
		queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
		
		rs_examTask = queryObj.execute( sql=sql ).getResult();
		
		/* 设置考试可用的时间 */
		timeTable = arrayNew(2);
		
		for(weekDay=1; weekDay lte 7; weekDay++){
			for(lecture=1; lecture lte 5; lecture++){
				timeTable[weekDay][lecture] = 0;
			}
		}

		/* 根据考试类型 选择加载时间设置数据 */
		switch ( rs_examTask.exam_type ) {
			
			case "M":
				/* 读取半期考试可用时间 */
				/* 第3位 是否用于半期排考 */
				sql = "SELECT wdidx, lecidx, props FROM t_timetable WHERE SUBSTR(props, 3, 1) = '1' AND lecidx IN ('1','2','3','4','5') ";
				
				break;
				
			case "F":
				/* 读取期末考试可用时间 */
				/* 第4位 是否用于期末集中排考 */
				sql = "SELECT  wdidx, lecidx, props FROM t_timetable WHERE SUBSTR(props, 4, 1) = '1' AND lecidx IN ('1','2','3','4','5') ";
				
				break;

			case "S":
				/* 读取分散考试可用时间 */
				/* 第5位 是否用于自主分散考试安排 */
				sql = "SELECT  wdidx, lecidx, props FROM t_timetable WHERE SUBSTR(props, 5, 1) = '1' AND lecidx IN ('1','2','3','4','5') ";
				
				break;
			
		}
		
		queryObj = new query( datasource=application.dnsSlave );
		
		rs_timeSet = queryObj.execute( sql=sql ).getResult();
		
		for ( i=1; i LTE rs_timeSet.recordCount; i++ ) {
			timeTable[rs_timeSet["wdidx"][i]][rs_timeSet["lecidx"][i]] = 1;
		}
		
		/* -------------- */
		/* 计算课表时间冲突 */
		/* -------------- */
		conflictSet = structNew();

		termId = rs_examTask.term_id;
		examWeek = rs_examTask.wid;
		
		/* 检查现有考试冲突 */
		sql = "SELECT task_id FROM t_examplan 
				WHERE cid = :courseId 
					  AND 
					  term_id = :termId 
					  AND 
					  exidx = :examIndex "; 
		
		queryObj = new query( datasource=application.dnsSlave ); 
		queryObj.addParam( name="courseId", value=rs_examTask.cid, cfsqltype="cf_sql_varchar" );
		queryObj.addParam( name="termId", value=rs_examTask.term_id, cfsqltype="cf_sql_char" );
		queryObj.addParam( name="examIndex", value=rs_examTask.exidx, cfsqltype="cf_sql_char" );
		
		rs_taskIds= queryObj.execute( sql=sql ).getResult(); 
		
		
		/* 考试时间 学生不能有课 */
		sql = "SELECT 
					a.tasktime, COUNT(DISTINCT d.stu_id) countStu 
				FROM 
					t_task_timetable a, 
					t_task_arrange b,
					t_student_course d 
				WHERE 
					b.task_id = a.task_id 
					AND 
					a.task_id = d.task_id 
					AND 
					b.term_id = :termId 
					AND 
					SUBSTR(a.widx, #int(examWeek)#, 1) = '1' 
					AND 
					EXISTS(
						SELECT 1 FROM t_student_course e 
						WHERE e.stu_id = d.stu_id 
							  AND 
							  e.task_id IN (:taskIds)
					)
				GROUP BY 
					a.tasktime "; 
					
		queryObj = new query( datasource=application.dnsSlave ); 
		queryObj.addParam( name="termId", value=rs_examTask.term_id, cfsqltype="cf_sql_char" );
		queryObj.addParam( name="taskIds", value=arrayToList(rs_taskIds["task_id"],"|"), cfsqltype="cf_sql_varchar", list=true, separator="|" );
		
		rs_conflict = queryObj.execute( sql=sql ).getResult(); 

		for ( i=1; i LTE rs_conflict.recordCount; i++ ) {

			lec = rs_conflict["tasktime"][i];
			sVal = rs_conflict["countStu"][i];
			
			switch ( listGetAt(lec, 3, '-@') ) {
				
				case "2":

					/* 标志该时间学生上课冲突 */
					
					if ( listGetAt(lec, 2, "-@") eq 6 ) {
						timeTable[listGetAt(lec, 1, "-@")][5] = -2;
					}
					else {
						timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")] = -2;
					}
					

					break;

				case "3":
					
					/* 标志该时间学生上课冲突 */
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")] = -2;
					
					break;
				
				case "4":
				case "5":
								
					/* 标志该时间学生上课冲突 */
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")] = -2;
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")+1] = -2;
					
					break;
				
				case "8":
					
					/* 标志该时间学生上课冲突 */
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")] = -2;
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")+1] = -2;
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")+2] = -2;
					timeTable[listGetAt(lec, 1, "-@")][listGetAt(lec, 2, "-@")+3] = -2;
					
					break;
				
				
			}
			
		}
	
		/* 学生不能同时安排两场考试 */
		sql = "SELECT 
					a.wdidx, a.cellidx 
				FROM 
					t_examtask a 
				WHERE 
					(a.task_exid > :examId OR a.task_exid < :examId) 
					AND 
					a.wdidx > '0' 
					AND 
					a.wid = :examWeek 		
					AND 
					a.term_id = :termId 
					AND 
					EXISTS(
						SELECT 1 FROM t_examplan b 
						WHERE 
							 b.cid = a.cid 
							 AND 
							 b.term_id = a.term_id 
							 AND 
							 b.exidx = a.exidx 
							 AND 
							 EXISTS(
								 SELECT 1 FROM t_student_course e
								 WHERE 
									  e.task_id = b.task_id 
									  AND 
									  EXISTS(
											SELECT 1 FROM t_student_course d 
											WHERE 
												 d.stu_id = e.stu_id 
												 AND 
												 d.task_id IN (:taskIds)
									  )
							 )
					)";
		
		queryObj = new query( datasource=application.dnsSlave ); 
		queryObj.addParam( name="examId", value=examId, cfsqltype="cf_sql_char" );
		queryObj.addParam( name="examWeek", value=examWeek, cfsqltype="cf_sql_char" );
		queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
		queryObj.addParam( name="taskIds", value=arrayToList(rs_taskIds["task_id"],"|"), cfsqltype="cf_sql_varchar", list=true, separator="|" );
		
		rs_conflictExam = queryObj.execute( sql=sql ).getResult(); 
		
		
		for ( i=1; i LTE rs_conflictExam.recordcount; i++){
			timeTable[rs_conflictExam["wdidx"][i]][rs_conflictExam["cellidx"][i]] = -3;
		}

		/* 检查教室是否足够 */
		studentCount = rs_examTask.examer_sum;
		campusId = rs_examTask.campus_id;
		termId = rs_examTask.term_id;
		examWeek = rs_examTask.wid;

		for(weekDay=1; weekDay lte 7; weekDay++){
			for(lecture=1; lecture lte 5; lecture++){
				
				if ( timeTable[weekDay][lecture] eq 1 ) {
					
					cells = 2;
					/* 如果为 第二讲 或 第五讲 则使用最长学时数 */
					if (lecture eq 2 or lecture eq 5) { cells = 3; }
					
					cellStart = mathAdvice.convertLectureIdxToCellStart(lecture);
					cellEnd = cellStart + cells -1;
					
					sql = "SELECT 
								CASE WHEN SUM(a.sits_exam) IS NULL THEN 0 ELSE SUM(a.sits_exam) END sumsitsExam 
							FROM 
								t_classroom a
							WHERE 
								SUBSTR(a.cr_usage, 3, 1) = '1' 
								AND 
								(a.campus_id = :campusId) 
								AND 
								NOT EXISTS(
									SELECT 1 FROM t_clsroom_timetable b 
									WHERE 
										b.cr_id = a.cr_id 
										AND 
										b.term_id = :termId 
										AND 
										b.wdidx = :weekDay 
										AND 
										NOT (b.cellidx + b.cellrelay - 1 < :cellStart OR b.cellidx > :cellEnd) 
										AND 
										SUBSTR(b.widx, #int(examWeek)#, 1) = '1' )";
					
					queryObj = new query( datasource=application.dnsSlave ); 
					queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
					queryObj.addParam( name="weekDay", value=weekDay, cfsqltype="cf_sql_char" );
					queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
					queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
					queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
					
					rs_clsroomCheck = queryObj.execute( sql=sql ).getResult();
					

					/* 如果可用考场座位数 没有超过应考人数10 */
					
					if ( rs_clsroomCheck.recordCount ) {
						
						if ( rs_clsroomCheck["sumsitsExam"][1] lt studentCount + 10 ) {
							timeTable[weekDay][lecture] = -4;
						}
					}
					else {
						timeTable[weekDay][lecture] = -4;
					}
					
				}
			
			}
		}
		
		/* 生成最终返回 可以排考的时间数据 */
		
		availableTimeSet = [];
		
		notDone = true;
		
		for(weekDay=1; weekDay lte 7; weekDay++){
			for(lecture=1; lecture lte 5; lecture++){
				
				if ( timeTable[weekDay][lecture] eq 1 and notDone) {
					
					
					transaction {
						
						/* 加载考试任务 */
						sql = "SELECT 
									t_examtask.task_prog, 
									t_examtask.term_id, 
									t_examtask.exidx, 
									t_examtask.cid, 
									t_course.course_name, 
									t_examtask.wid, 
									t_examtask.wdidx, 
									t_examtask.cellidx, 
									t_examtask.campus_id 
								FROM 
									t_examtask 
									INNER JOIN t_course ON t_course.cid = t_examtask.cid 
								WHERE 
									t_examtask.task_exid = :taskExid ";
									
						queryObj = new query( datasource=application.dnsMaster );
						queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
						
						rs_examTask = queryObj.execute( sql=sql ).getResult();
		
						/* 设置时间 */
						if ( rs_examTask.task_prog eq "0" ) {
						
							arrayAppend( progress, "正在将考试安排在周" & weekDay & "第" & lecture & "场" );
							
							/* 考试场次 */
							/* 保存考试时间安排 */
							/* 更新排考进度 */
							
							sql = "UPDATE t_examtask SET wdidx = :examWeekDay, cellidx = :cellIndex, task_prog = '1' WHERE task_exid = :examTaskId ";
							
							queryObj = new query( datasource=application.dnsMaster );
							queryObj.addParam( name="examWeekDay", value=weekDay, cfsqltype="cf_sql_char" );
							queryObj.addParam( name="cellIndex", value=lecture, cfsqltype="cf_sql_char" );
							queryObj.addParam( name="examTaskId", value=examId, cfsqltype="cf_sql_char" );
							
							queryObj.execute( sql=sql );
						
							/* 数据密闭 */
			
							/* 如果已经保存了学生考试安排 则全部删除 */
							sql = "DELETE FROM t_student_exam WHERE task_exid = :taskExid";
			
							queryObj = new query( datasource=application.dnsMaster );
							queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
							
							queryObj.execute( sql=sql );
						
							/* 如果已经保存了场地占用 则全部删除 */
							sql = "DELETE FROM t_clsroom_timetable WHERE crtime_id IN (SELECT crtime_id FROM t_clsroom_forexam WHERE task_exid = :taskExid)";
							
							queryObj = new query( datasource=application.dnsMaster );
							queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
							queryObj.execute( sql=sql );
														
						}
						
						/* 设置地点 */
						if ( rs_examTask.task_prog eq "1" ) {
						
							termId = rs_examTask.term_id;
							examIdx = rs_examTask.exidx;
							courseId = rs_examTask.cid;
							courseName = rs_examTask.course_name;
							
							/* 获取考试的教学班列表 */
							sql = "SELECT task_id FROM t_examplan 
									WHERE cid = :courseId 
										  AND 
										  term_id = :termId 
										  AND 
										  exidx = :examIndex "; 
							
							queryObj = new query( datasource=application.dnsMaster ); 
							queryObj.addParam( name="courseId", value=courseId, cfsqltype="cf_sql_varchar" );
							queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
							queryObj.addParam( name="examIndex", value=examIdx, cfsqltype="cf_sql_char" );
							
							rs_taskIds= queryObj.execute( sql=sql ).getResult(); 
				
							/* 选课且已缴费的学生 */
							sql = "SELECT 
										stu_id, scc_id 
									FROM  
										t_student_course 
									WHERE 
										task_id IN (:taskIds) 
										AND 
										SUBSTR(choose_prop, 2, 1) = '1' 
									ORDER BY 
										task_id "; 
							
							queryObj = new query( datasource=application.dnsMaster ); 
							queryObj.addParam( name="taskIds", value=arrayToList(rs_taskIds["task_id"],"|"), cfsqltype="cf_sql_varchar", list=true, separator="|" );
							rs_student = queryObj.execute( sql=sql ).getResult(); 
				
															
							/* 随机编排学生 进行1/3乱序交换 */
							/*
							for ( i=1; i lt arrayLen(studentArray); i=i+3 ) {
						
								p1 = randRange(1, int(arrayLen(studentArray)/2-1), "SHA1PRNG");
								p2 = randRange(int(arrayLen(studentArray)/2), arrayLen(studentArray), "SHA1PRNG");
						
								arraySwap(studentArray, p1, p2);
							}
							*/
		
							studentCount = rs_student.recordCount;
							
							arrayAppend( progress, "刷新参考人数为 " & studentCount & "人" );
							
							
							examWeek = int(rs_examTask.wid);
							examWeekDay = rs_examTask.wdidx;
							examCell = rs_examTask.cellidx;
							campusId = rs_examTask.campus_id;	
					
							examWeekIdx = mathAdvice.convertExamWeekIdx(examWeek);
					
							cells = 2;
							/* 如果为 第二讲 或 第五讲 则使用最长学时数 */
							if (examCell eq 2 or examCell eq 5) { cells = 3; }
					
							cellStart = mathAdvice.convertLectureIdxToCellStart(examCell);
							cellEnd = cellStart + cells -1;
					
							/* 首先尝试一个教室可以放下 */
							/* 大小适合 且尺寸最小 */
							sql = "SELECT 
										a.cr_id 
									FROM 
										t_classroom a 
									WHERE 
										SUBSTR(a.cr_usage, 3, 1) = '1' 
										AND 
										a.campus_id = :campusId 
										AND 
										a.sits_exam > :studentCount 
										AND 
										NOT EXISTS(
											SELECT 1 FROM t_clsroom_timetable b 
											WHERE 
											  b.cr_id = a.cr_id 
											  AND 
											  b.term_id = :termId 
											  AND 
											  b.wdidx = :weekDay 
											  AND 
											  NOT (b.cellidx + b.cellrelay - 1 < :cellStart OR b.cellidx > :cellEnd) 
											  AND 
											  SUBSTR(b.widx, #int(examWeek)#, 1) = '1' ) 
									ORDER BY 
										 a.sits_exam ";
							
							queryObj = new query( datasource=application.dnsMaster, maxRows=1 ); 
							queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
							queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
							queryObj.addParam( name="studentCount", value=studentCount+2, cfsqltype="cf_sql_integer" );
							queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
							queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
							queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
							
							rs_clsroom = queryObj.execute( sql=sql ).getResult();
				
				
							if ( rs_clsroom.recordCount ) {
							
									arrayAppend( progress, "可以安排在一个考场进行" );
							
									/* 一个考场即足够 则标注该考场已使用 */
									clsroomId = rs_clsroom.cr_id;

									sql = "SELECT classroom, sits_exam FROM t_classroom WHERE cr_id = :classroomId"; 
						
									queryObj = new query( datasource=application.dnsMaster );
									queryObj.addParam( name="classroomId", value=clsroomId, cfsqltype="cf_sql_char" );
									
									rs_classRoom = queryObj.execute( sql=sql ).getResult();
									
									sequenceClassroomTimeTable.setTermID(termId);
									sequenceClassroomTimeTable.setClassroomID(clsroomId);
									useIdx = sequenceClassroomTimeTable.getIDX();
									
									sequenceClassroomTimeTable.setIndex(useIdx);
									useId = sequenceClassroomTimeTable.getID();
									
									sql = "INSERT INTO t_clsroom_timetable 
													(
														 crtime_id,
														 uidx,
														 widx,
														 wdidx,
														 cellidx,
														 cellrelay,
														 term_id,
														 cr_id,
														 ut_id
													)VALUES(
														 :classRoomTimeID ,
														 :useIndex ,
														 :weekIndex ,
														 :weekDay ,
														 :cellStart ,
														 :cellLength ,
														 :termId,
														 :classRoom ,
														 :usage 
													)";
									
									queryObj = new Query(datasource = application.dnsMaster);
									queryObj.addParam(name ="ClassRoomTimeID", value=useId, cfsqltype="cf_sql_char");
									queryObj.addParam(name ="weekIndex", value=mathAdvice.convertExamWeekIdx(examWeek), cfsqltype="cf_sql_char");
									queryObj.addParam(name ="weekDay", value=examWeekDay, cfsqltype="cf_sql_char");
									queryObj.addParam(name ="cellStart", value=cellStart, cfsqltype="cf_sql_interger");
									queryObj.addParam(name ="cellLength", value=cells, cfsqltype="cf_sql_interger");
									queryObj.addParam(name ="useIndex", value=useIdx, cfsqltype="cf_sql_char");
									queryObj.addParam(name ="termId", value=termId, cfsqltype="cf_sql_char");
									queryObj.addParam(name ="classRoom", value=clsroomId, cfsqltype="cf_sql_char");
									queryObj.addParam(name ="usage", value="3", cfsqltype="cf_sql_char");
									queryObj.execute(sql = sql);
									
									sql = "INSERT INTO t_clsroom_forexam 
												(
													 crtime_id,
													 task_exid,
													 exam_course 
												)VALUES(
													 :ClassRoomTimeID ,
													 :taskExamID ,
													 :examCourse 
												)";
											
									queryObj = new Query(datasource = application.dnsMaster);
									queryObj.addParam(name ="ClassRoomTimeID", value=useId, cfsqltype="cf_sql_char");
									queryObj.addParam(name ="taskExamID", value=examId, cfsqltype="cf_sql_varchar");
									queryObj.addParam(name ="examCourse", value=courseName, cfsqltype="cf_sql_varchar");
									queryObj.execute(sql = sql);
				
									/* 依次编排学生座位及考场 */
									sitidx = 0;
							
									for ( i=1; i LTE rs_student.recordCount; i++){
					
										sitidx++;
					
										sequenceStudentExam.setTaskExamID(examId);
										sequenceStudentExam.setStudentID(rs_student["stu_id"][i]);
										
										stuExamId = sequenceStudentExam.getID();
										
										sql = "INSERT INTO t_student_exam(
															scex_id, 
															task_exid, 
															stu_id, 
															cr_id, 
															sitidx, 
															scc_id 
														)VALUES(
															:examerID, 
															:taskExid, 
															:studentId, 
															:classroomId, 
															:sitIndex, 
															:chooseId 
														)";
										
										queryObj = new query( datasource=application.dnsMaster );
										queryObj.addParam( name="examerID", value=stuExamId, cfsqltype="cf_sql_varchar" ); 
										queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
										queryObj.addParam( name="studentId", value=rs_student["stu_id"][i], cfsqltype="cf_sql_varchar" );
										queryObj.addParam( name="classroomId", value=clsroomId, cfsqltype="cf_sql_char" );
										queryObj.addParam( name="sitIndex", value=sitidx, cfsqltype="cf_sql_integer" );
										queryObj.addParam( name="chooseId", value=rs_student["scc_id"][i], cfsqltype="cf_sql_varchar" );
										
										queryObj.execute( sql=sql );
										
									}
									
									/* 刷新考试人数 */
							
									/* 更新考试状态为已安排场地 */
									sql = "UPDATE t_examtask SET examer_sum = :examSize, task_prog = :taskProg WHERE task_exid = :taskExamId ";
					 
									queryObj = new query( datasource=application.dnsMaster ); 
									queryObj.addParam( name="examSize", value=studentCount, cfsqltype="cf_sql_integer" ); 
									queryObj.addParam( name="taskProg", value="2", cfsqltype="cf_sql_char" ); 
									queryObj.addParam( name="taskExamId", value=examId, cfsqltype="cf_sql_char" ); 
									
									queryObj.execute( sql=sql );
					
									arrayAppend( rooms, [rs_classRoom.classroom, rs_classRoom.sits_exam, sitidx, 1, sitidx ] );
							
									structInsert(response, "success", true, true);
									
									/* 标注循环结束 */
									notDone = false;
							}
							else {
								
								/* 考试人数过多 一个考场无法安排 */
						
								arrayAppend( progress, "考试人数过多,单一考场无法安排; 尝试集中到楼层" );
						
								/* 首先尝试能否集中到某一个楼的某一个楼层 */
								/* 满足最大考试人数 最少的考场 */
								sql = "SELECT 
											a.b_id, 
											a.cr_floor, 
											SUM(a.sits_exam) sumExam, 
											COUNT(*) countCr 
										FROM 
											t_classroom a 
										WHERE 
											SUBSTR(a.cr_usage, 3, 1) = '1' 
											AND 
											a.campus_id = :campusId 
											AND 
											NOT EXISTS(
												SELECT 1 FROM t_clsroom_timetable b 
												WHERE 
												  b.cr_id = a.cr_id 
												  AND 
												  b.term_id = :termId 
												  AND 
												  b.wdidx = :weekDay 
												  AND 
												  NOT (b.cellidx + b.cellrelay - 1 < :cellStart OR b.cellidx > :cellEnd) 
												  AND 
												  SUBSTR(b.widx, #int(examWeek)#, 1) = '1' )
										GROUP BY 
											a.b_id, a.cr_floor 
										HAVING 
											SUM(a.sits_exam) > :studentCount  
										ORDER BY 
											COUNT(*) ";
								
								queryObj = new query( datasource=application.dnsMaster, maxRows=1 ); 
								queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="studentCount", value=studentCount+2, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
								
								rs_floor = queryObj.execute( sql=sql ).getResult();
				

								if ( rs_floor.recordCount ) {
							
									/* 可以在一个楼层安排下来 */
									sql = "SELECT 
												a.cr_id, 
												a.classroom, 
												a.sits_exam 
											FROM 
												t_classroom a 
											WHERE 
												SUBSTR(a.cr_usage, 3, 1) = '1' 
												AND 
												a.cr_floor = :floorId 
												AND 
												a.b_id = :buildingId 
												AND 
												a.campus_id = :campusId 
												AND 												
												NOT EXISTS(
													SELECT 1 FROM t_clsroom_timetable b 
													WHERE 
													  b.cr_id = a.cr_id 
													  AND 
													  b.term_id = :termId 
													  AND 
													  b.wdidx = :weekDay 
													  AND 
													  NOT (b.cellidx + b.cellrelay - 1 < :cellStart OR b.cellidx > :cellEnd) 
													  AND 
													  SUBSTR(b.widx, #int(examWeek)#, 1) = '1' ) 
											ORDER BY 
												a.classroom ";
									
									queryObj = new query( datasource=application.dnsMaster ); 
									queryObj.addParam( name="floorId", value=rs_floor.cr_floor, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="buildingId", value=rs_floor.b_id, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
									queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
									
									rs_clsroom = queryObj.execute( sql=sql ).getResult();
									
								}
								else {
							
									arrayAppend( progress, "无法集中到某个楼层; 将考试场地集中分布到可用教学楼的各楼层" );
							
									/* 无法安排在一个楼层 则调用更多的教室 */
									/* 按照教学楼和楼层进行排序 */
									sql = "SELECT 
												a.cr_id, 
												a.classroom, 
												a.sits_exam 
											FROM 
												t_classroom a 
											WHERE 
												SUBSTR(a.cr_usage, 3, 1) = '1' 
												AND 
												a.campus_id = :campusId 
												AND 												
												NOT EXISTS(
													SELECT 1 FROM t_clsroom_timetable b 
													WHERE 
													  b.cr_id = a.cr_id 
													  AND 
													  b.term_id = :termId 
													  AND 
													  b.wdidx = :weekDay 
													  AND 
													  NOT (b.cellidx + b.cellrelay - 1 < :cellStart OR b.cellidx > :cellEnd) 
													  AND 
													  SUBSTR(b.widx, #int(examWeek)#, 1) = '1' ) 
											ORDER BY 
												a.b_id, a.cr_floor, a.classroom ";
									
									queryObj = new query( datasource=application.dnsMaster ); 
									queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
									queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
									
									rs_clsroom = queryObj.execute( sql=sql ).getResult();								
							
								}
						
								sitsCount = 0;
						
								for ( i=1; i LTE rs_clsroom.recordCount; i++){
									sitsCount = sitsCount + rs_clsroom["sits_exam"][i];
								}
						
								arrayAppend( progress, "目前可用教室" & rs_clsroom.recordCount & "个, 考场最高容量" & sitsCount & "座" );
						
								if ( sitsCount gte studentCount ) {

									/* 教室足够 */
									/* 开始可用考场和人数 */
							
									clsroomToArrange = [];
									sitsUsed = 0;
							
									for ( i=1; i LTE rs_clsroom.recordCount; i++){
								
										sitsUsed = sitsUsed + rs_clsroom["sits_exam"][i];
								
										arrayAppend(clsroomToArrange, [ rs_clsroom["cr_id"][i], rs_clsroom["classroom"][i], rs_clsroom["sits_exam"][i], 0 ] );
								
										if ( sitsUsed gte studentCount ) {
											break;
										}
									}
							
									roomCount = arrayLen(clsroomToArrange);
							
									/* 平均分配学生座次 */
									studentAvgPerRoom = int( studentCount / roomCount );
									studentLeft = studentCount;
							
									/* 先按照平均数分配人数 */
									for ( i=1; i lte roomCount; i++ ) {
								
										if ( clsroomToArrange[i][3] gte studentAvgPerRoom ) {
											clsroomToArrange[i][4] = studentAvgPerRoom;
											studentLeft = studentLeft - studentAvgPerRoom;
										}
										else {
											clsroomToArrange[i][4] = clsroomToArrange[i][3];
											studentLeft = studentLeft - clsroomToArrange[i][3];
										}
								
									}
														
									/* 再平均分配剩余人数 */
									while ( studentLeft gt 0 ) {

										for ( i=1; i lte roomCount; i++ ) {
									
											if ( studentLeft eq 0) {
												break;
											}
									
											if ( clsroomToArrange[i][4] lt clsroomToArrange[i][3] ) {
												clsroomToArrange[i][4] ++;
												studentLeft --;
											}
									
										}
								
									}

									arrayAppend( progress, "平均分布考场学生到" & roomCount & "个考场" );
							
									studentStart = 0;
									studentEnd = 0;
							
									for ( clsroomTarget in clsroomToArrange ) {
								
										/* 标注该考场已用于考试 */
										sql = "SELECT classroom, sits_exam FROM t_classroom WHERE cr_id = :classroomId"; 
						
										queryObj = new query( datasource=application.dnsMaster );
										queryObj.addParam( name="classroomId", value=clsroomTarget[1], cfsqltype="cf_sql_char" );
										
										rs_classRoom = queryObj.execute( sql=sql ).getResult();
										
										sequenceClassroomTimeTable.setTermID(termId);
										sequenceClassroomTimeTable.setClassroomID(clsroomTarget[1]);
										useIdx = sequenceClassroomTimeTable.getIDX();
										
										sequenceClassroomTimeTable.setIndex(useIdx);
										useId = sequenceClassroomTimeTable.getID();
										
										sql = "INSERT INTO t_clsroom_timetable 
														(
															 crtime_id,
															 uidx,
															 widx,
															 wdidx,
															 cellidx,
															 cellrelay,
															 term_id,
															 cr_id,
															 ut_id
														)VALUES(
															 :classRoomTimeID ,
															 :useIndex ,
															 :weekIndex ,
															 :weekDay ,
															 :cellStart ,
															 :cellLength ,
															 :termId ,
															 :classRoom ,
															 :usage 
														)";
										
										queryObj = new Query(datasource = application.dnsMaster);
										queryObj.addParam(name ="ClassRoomTimeID", value=useId, cfsqltype="cf_sql_char");
										queryObj.addParam(name ="weekIndex", value=mathAdvice.convertExamWeekIdx(examWeek), cfsqltype="cf_sql_char");
										queryObj.addParam(name ="weekDay", value=examWeekDay, cfsqltype="cf_sql_char");
										queryObj.addParam(name ="cellStart", value=cellStart, cfsqltype="cf_sql_interger");
										queryObj.addParam(name ="cellLength", value=cells, cfsqltype="cf_sql_interger");
										queryObj.addParam(name ="useIndex", value=useIdx, cfsqltype="cf_sql_char");
										queryObj.addParam(name ="termId", value=termId, cfsqltype="cf_sql_char");
										queryObj.addParam(name ="classRoom", value=clsroomTarget[1], cfsqltype="cf_sql_char");
										queryObj.addParam(name ="usage", value="3", cfsqltype="cf_sql_char");
										queryObj.execute(sql = sql);
										
										sql = "INSERT INTO t_clsroom_forexam 
													(
														 crtime_id,
														 task_exid,
														 exam_course 
													)VALUES(
														 :ClassRoomTimeID ,
														 :taskExamID ,
														 :examCourse 
													)";
												
										queryObj = new Query(datasource = application.dnsMaster);
										queryObj.addParam(name ="ClassRoomTimeID", value=useId, cfsqltype="cf_sql_char");
										queryObj.addParam(name ="taskExamID", value=examId, cfsqltype="cf_sql_varchar");
										queryObj.addParam(name ="examCourse", value=courseName, cfsqltype="cf_sql_varchar");
										queryObj.execute(sql = sql);
				
								
										/* 依次编排学生座位及考场 */
										sitidx = 0;
								
										studentStart = studentEnd + 1;
										studentEnd = studentEnd + clsroomTarget[4];

										for ( i=studentStart; i lte studentEnd; i++ ) {
									
											sitidx++;
											
											sequenceStudentExam.setTaskExamID(examId);
											sequenceStudentExam.setStudentID(rs_student["stu_id"][i]);
											
											stuExamId = sequenceStudentExam.getID();
											
											sql = "INSERT INTO t_student_exam(
																scex_id, 
																task_exid, 
																stu_id, 
																cr_id, 
																sitidx, 
																scc_id 
															)VALUES(
																:examerID, 
																:taskExid, 
																:studentId, 
																:classroomId, 
																:sitIndex, 
																:chooseId 
															)";
											
											queryObj = new query( datasource=application.dnsMaster );
											queryObj.addParam( name="examerID", value=stuExamId, cfsqltype="cf_sql_varchar" ); 
											queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
											queryObj.addParam( name="studentId", value=rs_student["stu_id"][i], cfsqltype="cf_sql_varchar" );
											queryObj.addParam( name="classroomId", value=clsroomTarget[1], cfsqltype="cf_sql_char" );
											queryObj.addParam( name="sitIndex", value=sitidx, cfsqltype="cf_sql_integer" );
											queryObj.addParam( name="chooseId", value=rs_student["scc_id"][i], cfsqltype="cf_sql_varchar" );
											queryObj.execute( sql=sql );
																
										}
								
										arrayAppend( rooms, [rs_classRoom.classroom, rs_classRoom.sits_exam, clsroomTarget[4], studentStart, studentEnd ] );

								
									}
							
									/* 更新考试状态为已安排场地 */
									/* 刷新考试人数 */
									sql = "UPDATE t_examtask SET examer_sum = :examSize, task_prog = :taskProg WHERE task_exid = :taskExamId ";
					 
									queryObj = new query( datasource=application.dnsMaster ); 
									queryObj.addParam( name="examSize", value=studentCount, cfsqltype="cf_sql_integer" ); 
									queryObj.addParam( name="taskProg", value="2", cfsqltype="cf_sql_char" ); 
									queryObj.addParam( name="taskExamId", value=examId, cfsqltype="cf_sql_char" ); 
									queryObj.execute( sql=sql );
							
									arrayAppend( progress, "编排学生座次完成" );
							
									structInsert(response, "success", true, true);
									
									/* 标注循环结束 */
									notDone = false;
							
								}
								else {
									/* 考场不足 */
									structInsert(response, "reason", "当前考试时间没有足够的考场", true);
									
									arrayAppend( progress, "当前考试时间没有足够的考场" );
								}
				
							}
							
						}


					}
					
					
				}
				
			}
		}

		structInsert(response, "Progress", progress, true);
		structInsert(response, "ClassRoom", rooms, true);

	</cfscript>
</cfsilent><cfoutput>#jsonAdvice.encode(data:response, stringNumbers:true)#</cfoutput>